/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __THREAD_H__
#define __THREAD_H__

#include "BaseType.h"
#include "ThreadUtil.h"
#include "Singleton.h"
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <vector>

/**
 *  @file   Thread.h   
 *  @brief  线程
 */

namespace libemb{

/** 
 *  @class  ThreadAttr
 *  @brief  线程属性类	
 */
class ThreadAttr{
public:
	enum SCHED_POLICY_E
	{
		SCHED_POLICY_OTHER = SCHED_OTHER, /**< 0:普通调度策略,优先级只能设置为0 */
		SCHED_POLICY_FIFO = SCHED_FIFO,   /**< 1:不同优先级抢占,同等优先级先进先出,优先级可以设置为1(低)~99(高) */
		SCHED_POLICY_RR = SCHED_RR, 	  /**< 2:不同优先级抢占,同等优先级均分时间片,优先级可以设置为1(低)~99(高) */
	};

public:
	ThreadAttr(){};
	virtual ~ThreadAttr(){};
    /**
     * @brief 调度策略
     * @return int 
     * @note 可取值:SCHED_POLICY_FIFO(优先级1~99),SCHED_POLICY_RR(优先级1~99),SCHED_POLICY_OTHER(优先级固定为0)
     */
	int policy();
    /**
     * @brief 优先级
     * @return int 
     * @note 可取值:1~99,数字越大，优先级越高 
     */
	int priority();
    /**
     * @brief 属性继承方式
     * @return int 
     * @note PTHREAD_INHERIT_SCHED(继承自父线程,忽略当前设置的属性),PTHREAD_EXPLICIT_SCHED(采用当前设置的线程属性)
     */
	int inherit();
    /**
     * @brief 堆栈大小
     * @return int 
     * @note 最小值为PTHREAD_STACK_MIN(16384)
     */
	int stackSize();
private:
	friend class Thread;
	int m_policy{SCHED_POLICY_OTHER};
	int m_priority{0};
	int m_inherit{PTHREAD_INHERIT_SCHED};
	int m_stackSize{PTHREAD_STACK_MIN};
	
};

using ThreadEntry = std::function<void(void*)>; /**< 线程入口方法,必须是void(void*arg),否则在函数中可能无法使用成员变量!!! */

/**
 *  @class  Threading
 *  @brief  线程化类,用以线程化类成员函数
 */
class Threading{
DECL_CLASSNAME(Threading)
public:
	Threading(){};
	virtual ~Threading(){};
    /**
     * @brief 线程化
     * @param entry 线程入口
     * @param args 线程参数
     * @return false
     * @return true 
     */
	bool threading(ThreadEntry entry,void* args);
private:
	static void* startRoutine(void *arg);
};


/**
 *  @class  Runnable
 *  @brief  线程运行体,子类必须重写run方法.	
 */
class Runnable{
public:
	Runnable(){};
	virtual ~Runnable(){};
    /**
     * @brief 线程体主函数
     * @note 所有子类必须实现
     */
	virtual void run()=0;
    /**
     * @brief 判断线程体是否正在运行
     * @return true 
     * @return false 
     */
	bool isRunning();
protected:
    /**
     * @brief 退出线程体
     */
	void quit();
    /**
     *  @brief  增加线程取消点
     *  @param  void
     *  @return 成功返回true,失败返回false
     *  @note   当线程取消时,程序运行到此函数线程才退出
     */
    bool checkCancel();
private:
    friend class ThreadPool;
	friend class Thread;
    bool m_runFlag{false};
};


/**
 *  @file   Thread.h   
 *  @class  Thread
 *  @brief  线程类	
 */
class Thread{
DECL_CLASSNAME(Thread)
public:
	enum THREAD_STATE
	{
		STATE_EXIT=0,
	    STATE_START,
	    STATE_RUNNING,
	};
public:
	Thread();
	virtual ~Thread();
    /**
     *  @brief  初始化实时抢占系统
     *  @param  policy
     *  @param  priority
     *  @return 成功返回true,失败返回false
     *  @note   此函数仅限在linux-rt上使用
     */
	static bool initWithPreemptRT(int policy, int priority);
    /**
     *  @brief  微秒延时函数
     *  @param  us 要延时的微秒数
     *  @return void
     *  @note   函数休眠时,当前进程可能会让出CPU,引发进程调度
     *          注意使用usleep时,时间不能设置得太短,否则调度时
     *          进程间切换太频繁非常耗资源!!!推荐最小值为100us
     */
	static void usleep(int us);
    /**
     *  @brief  毫秒延时函数
     *  @param  ms 要延时的毫秒数
     *  @return void
     *  @note   函数休眠时,当前进程可能会让出CPU,引发进程调度
     */
	static void msleep(int ms);
    /**
     * @brief 设置线程属性
     * @param policy 
     * @param priority 
     * @param inherit 
     * @param stackSize 
     */
	void setAttribute(int policy, int priority, bool inherit=false,int stackSize=0);
    /**
     *  @brief  启动线程
     *  @param  runnable Runnable对象
     *  @return 成功返回true,失败返回false
     */
	bool start(const Runnable& runnable);
    /**
     *  @brief  停止线程
     *  @param  usTimeout 超时时间
     *  @return 成功返回true,失败返回false
     */
    bool stop(int usTimeout);
    /**
     *  @brief  强制退出线程
     *  @param  void
     *  @return void
     */
    bool forceQuit();
    /**
     *  @brief  判断线程是否正在运行
     *  @param  void
     *  @return 正在运行返回true,否则返回false
     */
	bool isRunning();
private:
	bool pthreadAttrSet(pthread_attr_t& pAttr);
    void threadMain();
    static void* startRoutine(void *arg);
private:
	Runnable* m_pRunnable{NULL};
	int m_threadStatus{STATE_EXIT};
	pthread_t m_threadID{0};
	pthread_attr_t m_attribute;
	ThreadAttr m_threadAttribute;
};

/**
 *  @class  ThreadPool
 *  @brief  线程池
 */
class ThreadPool:public Singleton<ThreadPool>{
DECL_CLASSNAME(ThreadPool)
DECL_SINGLETON(ThreadPool)
public:
    ~ThreadPool();
    /**
     *  @brief  线程池初始化
     *  @param  maxThreadCount 最大线程个数
     *  @return 成功返回true,失败返回false
     */
    bool init(int maxThreadCount);
    /**
     *  @brief  启动线程
     *  @param  runnable 线程运行体
     *  @param  priority 线程运行优先级
     *  @return 成功返回线程ID,失败返回STATUS_ERROR
     */
    int start(const Runnable& runnable,int policy, int priority);
    /**
     *  @brief  停止线程
     *  @param  threadID 线程id
     *  @return 成功返回true,失败返回false
     */
    bool cancel(int threadID);
    /**
     *  @brief  返回当前线程池最大线程个数
     *  @param  none
     *  @return 线程个数
     */
    int maxThreadCount();
    /**
     *  @brief  返回当前可用线程个数
     *  @param  none
     *  @return 线程个数
     */
    int idleThreadCount();
private:
    Mutex m_vectMutex;
    std::vector<std::unique_ptr<Thread>> m_threadVect;
    int m_maxThreadCount{0};
    int m_usedThreadCount{0};
};

}
#endif
